package jsen.tool.ddd.adapter.infrastructure.specification.base;

import lombok.Getter;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * 规格校验的入参
 * <p>
 * 1，复杂传递入参给规格
 * 2，如果规格校验失败有错误信息需要吐出，放在这里 addError
 * 3，判断是否符合规格 isValid
 * 4，控制哪些需要校验，这个是非常松散的支持，正真是否需要校验也是自己去判断，这里只给一个标识，至于这个哪些字段需要忽略，
 * 可选的方案是通过diff，对比哪些字段没有变更
 *
 * @author jsen
 * @date 2021/10/6
 */
public class SpecContext<T> {
    @Getter
    private final Map<String, String> specError;
    @Getter
    private final T data;
    // 当前spec中需要校验的SpecificationItem，默认全部，如果只校验特定几个就需要传入SpecItem，比如只校验变更的SpecItem
    private final Set<String> needSpecItem;

    protected SpecContext(Map<String, String> specError, T data, Set<String> needSpecItem) {
        this.specError = specError;
        this.data = data;
        this.needSpecItem = needSpecItem;
    }


    public void addError(String desc, String detail) {
        specError.put(desc, detail);
    }

    public boolean isValid() {
        return specError.isEmpty();
    }

    <E> boolean isNeedSpec(CompositeSpecification<E> specification) {
        return specification.getSpecConfig().isNeedCurrentSpec(needSpecItem);
    }

    public <S> SpecContext<S> subContext(Function<T, S> change) {
        return create(specError, change.apply(getData()), needSpecItem);
    }

    public static <T> SpecContext<T> create(T data) {
        return create(new HashMap<>(4), data, null);
    }

    private static <T> SpecContext<T> create(Map<String, String> specError, T data, Set<String> needSpecItem) {
        return new SpecContext<>(specError, data, needSpecItem);
    }

}
